/**
 * Copyright (C) 2011 The Android Open Source Project 
 * Emial : guoyil199@163.com
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */ 
package com.file;

import info.monitorenter.cpdetector.io.ASCIIDetector;
import info.monitorenter.cpdetector.io.CodepageDetectorProxy;
import info.monitorenter.cpdetector.io.JChardetFacade;
import info.monitorenter.cpdetector.io.ParsingDetector;
import info.monitorenter.cpdetector.io.UnicodeDetector;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Scanner;
import java.util.regex.Pattern;


public class CheckCN {
	 
	static int fileCount = 0;//文件总数
	static int wrong = 0 ;//含有中文字符的文件数
	static String regEx = "[\u4e00-\u9fa5]";   
    static Pattern pat = Pattern.compile(regEx);  
    static FileOutputStream fos = null;
    static OutputStreamWriter osw = null;

	public static void main(String[] args){
		Scanner sc = null;
		//long a = System.currentTimeMillis();
		
		    try {
		    	//每次重新执行的时候删除上次写入的文件
		    	File file = new File("D:\\cnFile.txt");
		    	file.delete();
		    	

		    	System.out.println("Please input the path as 'E:\\workspace\\jc6' : ");
		        //读取输入的路径
		    	sc = new Scanner(System.in);
		    	String filePath = sc.nextLine();
		    	//打开输出流
		    	fos = new FileOutputStream(new File("D:\\cnFile.txt"),true);
		    	osw = new OutputStreamWriter(fos,"UTF-8");
		    	
				//refreshFileList("E:\\workspace\\jc6");
		    	//开始检查文件
		    	refreshFileList(filePath);
			} catch (IOException e) {
				e.printStackTrace();
			}finally{
				 try {
					fos.close();
					osw.close();
					sc.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			//refreshFileList("E:\\workspace\\test\\ognl\\enhance");
		
		//System.out.print("运行时间为 ");
		//System.out.println(System.currentTimeMillis() - a);
		//输出检查结果
		System.out.println(fileCount+" files were checked , and "+wrong+" files containing the Chinese ,please check D:\\cnFile.txt");
	}

	//递归查找文件
     private static void refreshFileList(String strPath) throws IOException {
		File dir = new File(strPath);
		File[] files = dir.listFiles();
		
		if (files == null)
			return;
		for (int i = 0; i < files.length; i++) {
			int flag = 0 ;
			if (files[i].isDirectory()) {
				refreshFileList(files[i].getAbsolutePath());
			} else {
				 fileCount++;
				String strFileName = files[i].getAbsolutePath().toLowerCase();
				//System.out.println(getFileEncode(files[i].getAbsolutePath())+" ----" +files[i].getName());
				//截取文件格式
				String  fileName = strFileName.substring(strFileName.lastIndexOf(".")+1,strFileName.length());
				//不知为何  两种方法判断的时候都会吧class文件和jar文件当做是含有中文字符的文件
				//所以此处排除掉这class文件和jar文件不参与判断
				if(!"class".equals(fileName.toLowerCase())){
				//开始输入文件流，检查文件
					String enCode = getFileEncode(files[i].getAbsolutePath());
					if("void".equals(enCode)){
						enCode="UTF-8";
					}if("windows-1252".equals(enCode)){
						enCode="GBK";
					}
				FileInputStream fis = new FileInputStream(files[i].getAbsolutePath());
				InputStreamReader in = new InputStreamReader(fis,enCode);
			    BufferedReader br = new BufferedReader(in);
			    //用于记录行数  确定文件哪一行有中文
			    int lineCount = 0 ;
			    String line = null;
			    //逐行检查文件
			    while((line = br.readLine())!=null){
			    	 /////使用正则表达式进行判断
			    	lineCount++ ;
			    	/*Matcher matcher = pat.matcher(line);     
			        if (matcher.find())    {    
			        	//将含有中文的文件名称和中文所在行数写入文件夹
			        	osw.write(files[i].getAbsolutePath()+" ------- containing the Chinese at line "+lineCount+"\r\n");
			        	osw.flush();
			        	//System.out.println(files[i].getAbsolutePath()+"have china");
			        	 flag ++ ;
	    	            
			        }  */ 
			    	//////不适用正则表达式判断   两种判断方法在效率上不相上下
			    	     char[] charArray = line.toCharArray();  
			    	        for (int k = 0; k < charArray.length; k ++) {  
			    	          if ((charArray[k] >= 0x4e00) && (charArray[k] <= 0x9fbb)) {  
			    	            	//将含有中文的文件名称和中文所在行数写入文件夹
			    	            	osw.write(files[i].getAbsolutePath()+" ------- containing the Chinese at line "+lineCount+"\r\n");
			        	            osw.flush();
			    	                flag ++ ;
			    	                //wrong++;
			    	                if(flag!=0) k =charArray.length ;
			    	            }  
			    	       /*    byte[] bytes=(""+charArray[k]).getBytes(); 
			    	            if(bytes.length==2){ 
			    	            	int[] ints=new int[2]; 
			    	            	ints[0]=bytes[0]& 0xff; 
			    	            	ints[1]=bytes[1]& 0xff; 
			    	            	if(ints[0]>=0x81 && ints[0]<=0xFE && ints[1]>=0x40 && ints[1]<=0xFE){ 
			    	            		// isGB2312=true; 
			    	            		//将含有中文的文件名称和中文所在行数写入文件夹
				    	            	osw.write(files[i].getAbsolutePath()+" ------- containing the Chinese at line "+lineCount+"\r\n");
				        	            osw.flush();
				    	                flag ++ ;
			    	            	} 
			    	            	  if(flag!=0) k =charArray.length ;
			    	       }*/
				    } 
			    	        
			    	 
			    }
			    //flag!=0 说明该文件中含有中文
			    if(flag!=0) wrong++ ;
			    br.close();
			    in.close();
			    fis.close();
				}
			}
		}
	}
     //检查文件类型
     public static String getFileEncode(String path) {
 		/*
 		 * detector是探测器，它把探测任务交给具体的探测实现类的实例完成。
 		 * cpDetector内置了一些常用的探测实现类，这些探测实现类的实例可以通过add方法 加进来，如ParsingDetector、
 		 * JChardetFacade、ASCIIDetector、UnicodeDetector。
 		 * detector按照“谁最先返回非空的探测结果，就以该结果为准”的原则返回探测到的
 		 * 字符集编码。使用需要用到三个第三方JAR包：antlr.jar、chardet.jar和cpdetector.jar
 		 * cpDetector是基于统计学原理的，不保证完全正确。
 		 */
 		CodepageDetectorProxy detector = CodepageDetectorProxy.getInstance();
 		/*
 		 * ParsingDetector可用于检查HTML、XML等文件或字符流的编码,构造方法中的参数用于
 		 * 指示是否显示探测过程的详细信息，为false不显示。
 		 */
 		detector.add(new ParsingDetector(false));
 		/*
 		 * JChardetFacade封装了由Mozilla组织提供的JChardet，它可以完成大多数文件的编码
 		 * 测定。所以，一般有了这个探测器就可满足大多数项目的要求，如果你还不放心，可以
 		 * 再多加几个探测器，比如下面的ASCIIDetector、UnicodeDetector等。
 		 */
 		detector.add(JChardetFacade.getInstance());// 用到antlr.jar、chardet.jar
 		// ASCIIDetector用于ASCII编码测定
 		detector.add(ASCIIDetector.getInstance());
 		// UnicodeDetector用于Unicode家族编码的测定
 		detector.add(UnicodeDetector.getInstance());
 		java.nio.charset.Charset charset = null;
 		File f = new File(path);
 		try {
 			charset = detector.detectCodepage(f.toURI().toURL());
 		} catch (Exception ex) {
 			ex.printStackTrace();
 		}
 		if (charset != null)
 			return charset.name();
 		else
 			return null;
 	}
}
